package com.gitee.qdbp.base.controlling;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.gitee.qdbp.base.system.model.IAccount;

/**
 * 操作控制变量
 *
 * @author zhaohuihua
 * @version 160608
 */
public class ControllingVars implements IControllingVars {

    public static final ControllingVars me = new ControllingVars();

    private ThreadLocal<ThreadData> container = new ThreadDataLocal();

    protected ControllingVars() {
    }

    /** 当前登录用户(用于非WEB端发起的数据隔离) **/
    @Override
    public void setAccount(IAccount account) {
        container.get().setAccount(account);
    }

    /** 当前登录用户(用于非WEB端发起的数据隔离) **/
    @Override
    public IAccount getAccount() {
        return container.get().getAccount();
    }

    @Override
    public void addTraces(OperateTracesBean item) {
        container.get().addItem(item);
    }

    @Override
    public List<OperateTracesBean> getTraces(boolean clear) {
        return container.get().getItems(clear);
    }

    @Override
    public void addDbInvokeTimes() {
        container.get().addDbInvokeTimes();
    }

    @Override
    public Integer getDbInvokeTimes(boolean clear) {
        return container.get().getDbInvokeTimes(clear);
    }

    @Override
    public boolean useDataIsolation(String field) {
        return this.container.get().useDataIsolation(field);
    }

    @Override
    public void disableDataIsolation(String field, String... fields) {
        this.container.get().disableDataIsolation(field, fields);
    }

    @Override
    public void enableDataIsolation(String field, String... fields) {
        this.container.get().enableDataIsolation(field, fields);
    }

    @Override
    public void put(String group, String key, Object value) {
        this.container.get().put(key + "@" + group, value);
    }

    @Override
    public Object get(String group, String key) {
        return this.container.get().get(key + "@" + group);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T get(String group, String key, Class<T> clazz) {
        return (T) this.container.get().get(key + "@" + group);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> List<T> getList(String group, String key, Class<T> clazz) {
        return (List<T>) this.container.get().get(key + "@" + group);
    }

    /** 获取本次操作的开始时间 **/
    @Override
    public Date getStartTime(boolean clear) {
        return this.container.get().getStartTime(clear);
    }

    @Override
    public void start() {
        // 开始一次新的操作, 清空操作日志, 记录开始时间
        this.container.remove();
        this.container.get().start();
    }

    @Override
    public void clear() {
        container.remove();
    }

    private static class ThreadDataLocal extends ThreadLocal<ThreadData> {

        protected ThreadData initialValue() {
            return new ThreadData();
        }
    }

    public static class ThreadData {

        private Date startTime;

        private IAccount account;

        private Integer dbInvokeTimes;

        private List<OperateTracesBean> items;

        private Map<String, Boolean> dataIsolationFields;

        private Map<String, Object> extra;

        public ThreadData() {
            dataIsolationFields = new HashMap<>();
        }

        public void start() {
            this.startTime = new Date();
        }

        public Date getStartTime(boolean clear) {
            Date time = this.startTime;
            if (clear) {
                this.startTime = null;
            }
            return time;
        }

        /** 当前登录用户(用于非WEB端发起的数据隔离) **/
        public void setAccount(IAccount account) {
            this.account = account;
        }

        /** 当前登录用户(用于非WEB端发起的数据隔离) **/
        public IAccount getAccount() {
            return account;
        }

        public boolean useDataIsolation(String field) {
            if (dataIsolationFields.containsKey(field)) {
                return dataIsolationFields.get(field);
            } else {
                return true;
            }
        }

        public void disableDataIsolation(String field, String... fields) {
            dataIsolationFields.put(field, false);
            if (fields != null) {
                for (String s : fields) {
                    dataIsolationFields.put(s, false);
                }
            }
        }

        public void enableDataIsolation(String field, String... fields) {
            dataIsolationFields.put(field, true);
            if (fields != null) {
                for (String s : fields) {
                    dataIsolationFields.put(s, true);
                }
            }
        }

        public void addDbInvokeTimes() {
            if (this.dbInvokeTimes == null) {
                this.dbInvokeTimes = 1;
            } else {
                this.dbInvokeTimes++;
            }
        }

        public Integer getDbInvokeTimes(boolean clear) {
            Integer times = this.dbInvokeTimes;
            if (clear) {
                this.dbInvokeTimes = null;
            }
            return times;
        }

        public List<OperateTracesBean> getItems(boolean clear) {
            List<OperateTracesBean> items = this.items;
            if (clear) {
                this.items = null;
            }
            return items;
        }

        public void setItems(List<OperateTracesBean> items) {
            this.items = items;
        }

        public void addItem(OperateTracesBean item) {
            if (this.items == null) {
                this.items = new ArrayList<>();
            }
            this.items.add(item);
        }

        /** 附加数据 **/
        public Object get(String key) {
            return this.extra == null ? null : this.extra.get(key);
        }

        /** 附加数据 **/
        public void put(String key, Object value) {
            if (this.extra == null) {
                this.extra = new HashMap<>();
            }
            this.extra.put(key, value);
        }
    }
}
